﻿using HDS.Data;
using HDS.IService.Master;
using HDS.Model;
using HDS.Model.Entity.Log;
using HDS.Model.Entity.Master;
using HDS.Model.Entity.View;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace HDS.Service.Master
{
    public class DistributorService : IDistributorService
    {
        private MasterDbContext dbContext = new MasterDbContext();
        private LogDbContext logDbContext = new LogDbContext();

        #region config

        public async Task<DistributorConfig> GetConfig(string distributor)
        {
            return await dbContext.DistributorConfig.GetSingleAsync(e => e.Distributor.Equals(distributor));
        }

        public async Task<List<DistributorConfig>> GetConfigList(Expression<Func<DistributorConfig, bool>> whereExpression)
        {
            return await dbContext.Db.Queryable<DistributorConfig>().WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }

        public async Task<bool> SaveConfig(string distributor, bool isonline, string remark, int updatedBy, string updatedByName, DateTime updatedTime)
        {
            if (await dbContext.DistributorConfig.UpdateAsync(e => new DistributorConfig { Isonline = isonline, Remark = remark }, e => e.Distributor.Equals(distributor)))
            {
                await logDbContext.UpdateLog.InsertAsync(new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "SaveDistributorConfig",
                    LogText = $"Save Distributor Config, {distributor}|{isonline}|{remark}",
                    LogLevel = LogLevel.Information,
                    BusinessId = distributor,
                    UpdatedBy = updatedBy,
                    UpdatedByName = updatedByName,
                    UpdatedTime = updatedTime,
                });

                return true;
            }

            return false;
        }

        #endregion

        #region hotel data

        public const string VDistributorHotelSQL = "SELECT dh.`id`, dh.`hotel_id`, dh.`distributor`, dh.`distributor_hotel_id`, dh.`distributor_hotel_id1`, dh.`distributor_city_id`, dh.`distributor_city_name`, dh.`distributor_weight`, dh.`hotel_md5`, dh.`isonline`, dh.`push_status`, dh.`push_error`, dh.`push_result`, dh.`updated_by`, dh.`updated_by_name`, dh.`updated_time`, h.`hotel_name_en`, h.`hotel_name_cn`, h.`hotel_star`, h.`country_code`, h.`country_name`, h.`province_code`, h.`province_name`, h.`city_code`, h.`city_name`, h.`zone_code`, h.`zone_name`, h.`postalcode`, h.`hotel_address_en`, h.`hotel_address_cn`, h.`hotel_longitude`, h.`hotel_latitude`, h.`hotel_tel`, h.`hotel_fax`, h.`hotel_email`, h.`hotel_web`, h.`hotel_status`, h.`hotel_md5` hotel_md5_new FROM `distributor_hotel` dh LEFT JOIN hotel h ON dh.`hotel_id` = h.`hotel_id`";
        public const string VDistributorRoomSQL = "SELECT r.`room_id`, r.`hotel_id`, r.`room_name_en`, r.`room_name_cn`, r.`room_area`, r.`max_occupancy`, r.`room_beds`, r.`room_status`, r.`room_md5` room_md5_new, r.`third_party_id`, dr.`distributor`, dr.`distributor_hotel_id`, dr.`distributor_room_id`, dr.`distributor_room_id1`, dr.`room_md5`, dr.`push_status`, dr.`push_error`, dr.`push_result`, dr.`updated_by`, dr.`updated_by_name`, dr.`updated_time` FROM `hotel_room` r LEFT JOIN `distributor_room` dr ON dr.`hotel_id` = r.`hotel_id` AND dr.`room_id` = r.`room_id`";

        public async Task<VDistributorHotel> GetHotel(string distributor, int hotelId)
        {
            return await dbContext.Db.SqlQueryable<VDistributorHotel>(VDistributorHotelSQL).Where(e => e.Distributor.Equals(distributor) && e.HotelId.Equals(hotelId)).FirstAsync();
        }

        public async Task<DataPagingModel<VDistributorHotel>> GetHotelList(int pageIndex, int pageSize, Expression<Func<VDistributorHotel, bool>> whereExpression, string whereSql)
        {
            RefAsync<int> total = 0;
            var rows = await dbContext.Db.SqlQueryable<VDistributorHotel>(VDistributorHotelSQL)
                .WhereIF(whereExpression != null, whereExpression)
                .WhereIF(!string.IsNullOrEmpty(whereSql), whereSql)
                .OrderBy(e => e.Id, OrderByType.Desc)
                .ToPageListAsync(pageIndex, pageSize, total);

            return new DataPagingModel<VDistributorHotel>
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageTotal = (total.Value + pageSize - 1) / pageSize,
                Total = total.Value,
                Rows = rows
            };
        }

        public async Task<List<VDistributorRoom>> GetRoomList(string distributor, int hotelId)
        {
            var sql = VDistributorRoomSQL;
            sql += $" AND dr.distributor = '{distributor.ToSqlFilter()}'";
            sql += $" WHERE r.hotel_id = {hotelId}";
            return await dbContext.Db.SqlQueryable<VDistributorRoom>(sql).ToListAsync();
        }

        public async Task<int> AddHotels(string distributor, int[] hotelIds, string[] hotelMd5s, int updatedBy, string updatedByName, DateTime updatedTime)
        {
            var oldHotelIds = dbContext.Db.Queryable<DistributorHotel>().Where(e => e.Distributor.Equals(distributor) && hotelIds.Contains(e.HotelId)).Select(e => e.HotelId).ToArray();
            var hotelList = new List<DistributorHotel>();
            for (var i = 0;i < hotelIds.Length;i++)
            {
                if (oldHotelIds.Contains(hotelIds[i]))
                    continue;

                hotelList.Add(new DistributorHotel
                {
                    HotelId = hotelIds[i],
                    Distributor = distributor,
                    DistributorHotelId = "",
                    DistributorHotelId1 = "",
                    DistributorCityId = "",
                    DistributorCityName = "",
                    DistributorWeight = 0,
                    HotelMd5 = hotelMd5s[i],
                    Isonline = true,
                    PushError = "",
                    PushStatus = Model.PushStatus.NotPush,
                    PushResult = Model.PushResult.NotPush,
                    UpdatedBy = updatedBy,
                    UpdatedByName = updatedByName,
                    UpdatedTime = updatedTime,
                });
            }

            if (hotelList.Count > 0)
            {
                await dbContext.DistributorHotel.InsertRangeAsync(hotelList);

                var updateLogs = new List<UpdateLog>();
                foreach (var entity in hotelList)
                {
                    updateLogs.Add(new UpdateLog
                    {
                        LogType = UpdateLogType.StaticData,
                        LogSubType = "AddDistributorHotel",
                        LogText = $"Add Distributor Hotel, {entity.Distributor}|{entity.HotelId}",
                        LogLevel = LogLevel.Information,
                        BusinessId = entity.HotelId.ToString(),
                        UpdatedBy = updatedBy,
                        UpdatedByName = updatedByName,
                        UpdatedTime = updatedTime,
                    });
                }
                await logDbContext.UpdateLog.InsertRangeAsync(updateLogs);

                return hotelList.Count;
            }

            return 0;
        }

        public async Task SetCity(string distributor, int hotelId, string distributorCityId, string distributorCityName, int updatedBy, string updatedByName, DateTime updatedTime)
        {
            if (await dbContext.DistributorHotel.UpdateAsync(e => new DistributorHotel { DistributorCityId = distributorCityId, DistributorCityName = distributorCityName }, e => e.Distributor.Equals(distributor) && e.HotelId.Equals(hotelId)))
            {
                await logDbContext.UpdateLog.InsertAsync(new UpdateLog
                {
                    LogType = UpdateLogType.StaticData,
                    LogSubType = "SetCity",
                    LogText = $"Set City, {distributor}|{hotelId}|{distributorCityId}|{distributorCityName}",
                    LogLevel = LogLevel.Information,
                    BusinessId = hotelId.ToString(),
                    UpdatedBy = updatedBy,
                    UpdatedByName = updatedByName,
                    UpdatedTime = updatedTime,
                });
            }
        }

        public async Task SetOnline(string[] distributors, int[] hotelIds, int updatedBy, string updatedByName, DateTime updatedTime)
        {
            for (var i = 0; i < distributors.Length; i++)
            {
                var distributor = distributors[i];
                var hotelId = hotelIds[i];
                if (await dbContext.DistributorHotel.UpdateAsync(e => new DistributorHotel { Isonline = true }, e => e.Distributor.Equals(distributor) && e.HotelId.Equals(hotelId) && !e.Isonline))
                {
                    await logDbContext.UpdateLog.InsertAsync(new UpdateLog
                    {
                        LogType = UpdateLogType.StaticData,
                        LogSubType = "SetOnline",
                        LogText = $"Set Online, {distributor}|{hotelId}",
                        LogLevel = LogLevel.Information,
                        BusinessId = hotelId.ToString(),
                        UpdatedBy = updatedBy,
                        UpdatedByName = updatedByName,
                        UpdatedTime = updatedTime,
                    });
                }
            }
        }

        public async Task SetOffline(string[] distributors, int[] hotelIds, int updatedBy, string updatedByName, DateTime updatedTime)
        {
            for (var i = 0; i < distributors.Length; i++)
            {
                var distributor = distributors[i];
                var hotelId = hotelIds[i];
                if (await dbContext.DistributorHotel.UpdateAsync(e => new DistributorHotel { Isonline = false }, e => e.Distributor.Equals(distributor) && e.HotelId.Equals(hotelId) && e.Isonline))
                {
                    await logDbContext.UpdateLog.InsertAsync(new UpdateLog
                    {
                        LogType = UpdateLogType.StaticData,
                        LogSubType = "SetOffline",
                        LogText = $"Set Offline, {distributor}|{hotelId}",
                        LogLevel = LogLevel.Information,
                        BusinessId = hotelId.ToString(),
                        UpdatedBy = updatedBy,
                        UpdatedByName = updatedByName,
                        UpdatedTime = updatedTime,
                    });
                }
            }
        }

        #endregion

        #region supplier config

        public async Task<DistributorSupplierSetting> GetSupplierSetting(string distributor, string supplier)
        {
            return await dbContext.DistributorSupplierSetting.GetSingleAsync(e => e.Distributor.Equals(distributor) && e.Supplier.Equals(supplier));
        }

        public async Task<List<DistributorSupplierSetting>> GetSupplierSettingList(Expression<Func<DistributorSupplierSetting, bool>> whereExpression)
        {
            return await dbContext.Db.Queryable<DistributorSupplierSetting>().WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }

        public async Task<bool> SaveSupplierSetting(DistributorSupplierSetting entity)
        {
            var old = await dbContext.DistributorSupplierSetting.GetSingleAsync(e => e.Distributor.Equals(entity.Distributor) && e.Supplier.Equals(entity.Supplier));
            if (old == null)
            {
                return await dbContext.DistributorSupplierSetting.InsertAsync(entity);
            }
            else
            {
                return await dbContext.DistributorSupplierSetting.UpdateAsync(entity);
            }
        }

        #endregion

        #region hotel setting

        public async Task<List<DistributorHotelSetting>> GetHotelSettingList(Expression<Func<DistributorHotelSetting, bool>> whereExpression)
        {
            return await dbContext.Db.Queryable<DistributorHotelSetting>().WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }

        public async Task<bool> SaveHotelSetting(DistributorHotelSetting entity)
        {
            var old = await dbContext.DistributorHotelSetting.GetSingleAsync(e => e.Distributor.Equals(entity.Distributor) && e.Supplier.Equals(entity.Supplier) && e.HotelId.Equals(entity.HotelId));
            if (old == null)
            {
                return await dbContext.DistributorHotelSetting.InsertAsync(entity);
            }
            else
            {
                return await dbContext.DistributorHotelSetting.UpdateAsync(entity);
            }
        }

        public async Task<bool> DeleteHotelSetting(int hotelId, string distributor, string supplier) 
        {
            return await dbContext.DistributorHotelSetting.DeleteAsync(e => e.Distributor.Equals(distributor) && e.Supplier.Equals(supplier) && e.HotelId.Equals(hotelId));
        }

        #endregion
    }
}
